package com.suredy.app.dm.ctrl;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import javax.transaction.Transactional;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.SimpleExpression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.suredy.app.dm.constants.DmOpTypes;
import com.suredy.app.dm.model.DmOpLog;
import com.suredy.app.porject.constants.ContractType;
import com.suredy.app.porject.ctrl.view.ViewRoleCtrl;
import com.suredy.app.porject.ctrl.view.ViewRoleCtrlForBid;
import com.suredy.app.porject.model.Bid;
import com.suredy.app.porject.model.BidAgency;
import com.suredy.app.porject.model.Biddinger;
import com.suredy.app.porject.model.Contract;
import com.suredy.app.porject.model.vo.BidEditModel;
import com.suredy.app.porject.model.vo.MainContractEditModel;
import com.suredy.app.porject.service.BidAgencySrv;
import com.suredy.app.porject.service.BidSrv;
import com.suredy.app.porject.service.BiddingerSrv;
import com.suredy.app.porject.service.ContractSrv;
import com.suredy.app.porject.service.ProjectCompany;
import com.suredy.app.porject.service.ProjectConstants;
import com.suredy.core.mvc.model.MessageModel;

/**
 * 数据维护入口
 * 
 * @author VIVID.G
 * @since 2016-3-31
 * @version v0.1
 */
@Controller
@RequestMapping("/dm")
public class DataManagerCtrl extends DataManagerCtrlHelper {

	@Autowired
	private ContractSrv contractSrv;

	@Autowired
	private BidSrv bidSrv;

	@Autowired
	private ProjectCompany company;

	@Autowired
	private ProjectConstants constants;

	@Autowired
	private BiddingerSrv biddingerSrv;

	@Autowired
	private BidAgencySrv bidAgencySrv;

	@RequestMapping
	public String index(String type, Model model) {
		String view = "app/dm/index";

		model.addAttribute("type", StringUtils.isBlank(type) ? "c" : type);

		return view;
	}

	@RequestMapping("/search")
	public String search(String type, String key, Integer page, Integer pageSize, Model model) {
		String view = "app/dm/blank";

		if (page == null || page < 1)
			page = 1;

		if (pageSize == null || pageSize < 1)
			pageSize = 30;

		model.addAttribute("type", type);
		model.addAttribute("key", key);
		model.addAttribute("page", page);
		model.addAttribute("pageSize", pageSize);

		if ("c".equalsIgnoreCase(type)) {
			return this.contractData(key, page, pageSize, model);
		}

		if ("b".equalsIgnoreCase(type)) {
			return this.bidData(key, page, pageSize, model);
		}

		return view;
	}

	@RequestMapping(value = "/contract-del", method = RequestMethod.POST)
	@ResponseBody
	@Transactional
	@SuppressWarnings("unchecked")
	public Object contractDel(String[] ids) {
		if (ids == null || ids.length < 1)
			return MessageModel.createErrorMessage("请选择需要删除的数据！", null);

		ViewRoleCtrl vrc = new ViewRoleCtrl(this.getUser());

		if (!vrc.isCanDelContract()) {
			return MessageModel.createErrorMessage("您无法删除数据", null);
		}

		DetachedCriteria dc = this.contractSrv.getDc(null);
		dc.add(Restrictions.in("id", ids));

		List<Contract> data = (List<Contract>) this.contractSrv.readByCriteria(dc);

		if (data != null && !data.isEmpty()) {
			for (Contract c : data) {
				this.contractSrv.delete(c);
			}

			// 记录操作日志
			this.recordContractDelLog(data);
		}

		return MessageModel.createSuccessMessage("操作完成！", null);
	}

	@RequestMapping(value = "/bid-del", method = RequestMethod.POST)
	@ResponseBody
	@Transactional
	@SuppressWarnings("unchecked")
	public Object bidDel(String[] ids) {
		if (ids == null || ids.length < 1)
			return MessageModel.createErrorMessage("请选择需要删除的数据！", null);

		ViewRoleCtrl vrc = new ViewRoleCtrl(this.getUser());

		if (!vrc.isCanDelBid()) {
			return MessageModel.createErrorMessage("您无法删除数据", null);
		}

		DetachedCriteria dc = this.bidSrv.getDc(null);
		dc.add(Restrictions.in("id", ids));

		List<Bid> data = (List<Bid>) this.bidSrv.readByCriteria(dc);

		if (data != null && !data.isEmpty()) {
			for (Bid c : data) {
				this.bidSrv.delete(c);
			}

			// 记录操作日志
			this.recordBidDelLog(data);
		}

		return MessageModel.createSuccessMessage("操作完成！", null);
	}

	@RequestMapping(value = "/contract-edit/{id}", method = RequestMethod.GET)
	public String contractEditForm(@PathVariable String id, Model model) {
		String view = "app/dm/contract-edit";

		ViewRoleCtrl vrc = new ViewRoleCtrl(this.getUser());

		if (!vrc.isCanEditorContract()) {
			model.addAttribute("cannotedit", true);
			return view;
		}

		if (StringUtils.isBlank(id)) {
			model.addAttribute("invalid", true);
			return view;
		}

		Contract data = this.contractSrv.get(id);

		if (data == null) {
			model.addAttribute("notfound", true);
			return view;
		}

		List<String> ownCompany = this.company.getAllCompany();
		if (ownCompany == null || ownCompany.isEmpty()) {
			ownCompany = new ArrayList<String>();
			ownCompany.add(this.getUser().getOrgName());
		}

		switch (data.getType()) {
			case MAIN:
				view = "app/dm/contract-edit-from-bid";

				model.addAttribute("jiesuanWay", this.constants.getContractJiesuanWay(null));
				model.addAttribute("biddingers", this.getBiddingers());
				model.addAttribute("company", ownCompany);
				model.addAttribute("data", data);

				break;
			case A_CONTRACT:
			case B_CONTRACT:
				view = "app/dm/contract-edit";

				model.addAttribute("jiesuanWay", this.constants.getContractJiesuanWay(null));
				model.addAttribute("biddingers", this.getBiddingers());
				model.addAttribute("company", ownCompany);
				model.addAttribute("data", data);

				break;
			default:
				// 不是主合同，直接返回错误
				model.addAttribute("data", data);
				model.addAttribute("errortype", true);
				return view;
		}

		return view;
	}

	@RequestMapping(value = "/bid-edit/{id}", method = RequestMethod.GET)
	public String bidEditForm(@PathVariable String id, Model model) {
		String view = "app/dm/bid-edit";

		ViewRoleCtrl vrc = new ViewRoleCtrl(this.getUser());

		if (!vrc.isCanEditBid()) {
			model.addAttribute("cannotedit", true);
			return view;
		}

		if (StringUtils.isBlank(id)) {
			model.addAttribute("invalid", true);
			return view;
		}

		Bid data = this.bidSrv.get(id);

		if (data == null) {
			model.addAttribute("invalid", true);
			return view;
		}

		model.addAttribute("biddingers", this.getBiddingers());
		model.addAttribute("bidAgencys", this.getBidAgencys());
		model.addAttribute("bidTypes", this.constants.getBidTypes(null));
		model.addAttribute("bidWays", this.constants.getBidWays(null));
		model.addAttribute("bidQuotationType", this.constants.getBidQuotationType(null));

		List<String> ownCompany = this.company.getAllCompany();
		if (ownCompany == null || ownCompany.isEmpty()) {
			ownCompany = new ArrayList<String>();
			ownCompany.add(this.getUser().getOrgName());
		}

		model.addAttribute("ownCompany", ownCompany);
		model.addAttribute("roles", new ViewRoleCtrlForBid(data, this.getUser()));

		model.addAttribute("data", data);

		return view;
	}

	@RequestMapping(value = "/contract-edit", method = RequestMethod.POST)
	@ResponseBody
	public Object editContract(MainContractEditModel contract) {
		ViewRoleCtrl vrc = new ViewRoleCtrl(this.getUser());

		if (!vrc.isCanEditorContract()) {
			return new MessageModel(false, "您无法编辑数据！", null);
		}

		if (contract == null || StringUtils.isBlank(contract.getId()))
			return new MessageModel(false, "无效的合同信息！", null);

		Contract data = this.contractSrv.get(contract.getId());

		if (data == null || StringUtils.isBlank(data.getId()))
			return new MessageModel(false, "保存合同信息失败！", null);

		MainContractEditModel old = this.storeOldData(data);

		if (old == null)
			return new MessageModel(false, "系统内部错误！", null);

		try {
			PropertyUtils.copyProperties(data, contract);
		} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
			return new MessageModel(false, "保存合同信息失败！\n" + e.getMessage(), null);
		}

		data = this.contractSrv.update(data);

		if (data == null || StringUtils.isBlank(data.getId()))
			return new MessageModel(false, "保存合同信息失败！", null);

		// 记录日志
		this.recordContractUpdateLog(old, contract);

		return new MessageModel(true, "操作成功！", data.getId());
	}

	@RequestMapping(value = "/bid-edit", method = RequestMethod.POST)
	@ResponseBody
	public Object editBid(BidEditModel bid) {
		ViewRoleCtrl vrc = new ViewRoleCtrl(this.getUser());

		if (!vrc.isCanEditBid()) {
			return new MessageModel(false, "您无法编辑数据！", null);
		}

		if (bid == null || StringUtils.isBlank(bid.getId()))
			return new MessageModel(false, "无效的招标信息！", null);

		Bid data = this.bidSrv.get(bid.getId());

		if (data == null || StringUtils.isBlank(data.getId()))
			return new MessageModel(false, "保存招标信息失败！", null);

		BidEditModel old = this.storeOldData(data);

		if (old == null)
			return new MessageModel(false, "系统内部错误！", null);

		try {
			PropertyUtils.copyProperties(data, bid);
		} catch (Exception e) {
			return new MessageModel(false, "保存招标信息失败！\n" + e.getMessage(), null);
		}

		data = this.bidSrv.update(data);

		if (data == null || StringUtils.isBlank(data.getId()))
			return new MessageModel(false, "保存招标信息失败！", null);

		// 记录日志
		this.recordBidUpdateLog(old, bid);

		return new MessageModel(true, "操作成功！", data.getId());
	}

	@RequestMapping("/op-logs")
	public String dmOpLogs(DmOpLog search, Integer page, Integer pageSize, Model model) {
		String view = "app/dm/op-logs";

		if (page == null || page < 1)
			page = 1;

		if (pageSize == null || pageSize < 1)
			pageSize = 30;

		model.addAttribute("data", this.dmOpLogSrv.readByEntity(search, page, pageSize));
		model.addAttribute("page", page);
		model.addAttribute("pageSize", pageSize);
		model.addAttribute("count", this.dmOpLogSrv.getCountByEntity(search));
		model.addAttribute("search", search);
		model.addAttribute("types", DmOpTypes.values());

		return view;
	}

	public String contractData(String key, int page, int pageSize, Model model) {
		String view = "app/dm/contract-list";

		ProjectionList pl = Projections.projectionList();
		pl.add(Property.forName("id"));
		pl.add(Property.forName("no"));
		pl.add(Property.forName("name"));
		pl.add(Property.forName("bid.id"));

		DetachedCriteria dc = this.contractSrv.getDc(null);
		dc.setProjection(pl);
		dc.add(Restrictions.in("type", ContractType.MAIN_CONTRACT_TYPES));
		dc.addOrder(Order.asc("no"));
		dc.addOrder(Order.asc("name"));

		if (!StringUtils.isBlank(key)) {
			SimpleExpression r1 = Restrictions.like("no", key, MatchMode.ANYWHERE);
			SimpleExpression r2 = Restrictions.like("name", key, MatchMode.ANYWHERE);

			dc.add(Restrictions.or(r1, r2));
		}

		model.addAttribute("data", this.contractSrv.readByCriteria(dc, page, pageSize));
		model.addAttribute("count", this.contractSrv.getCountByCriteria(dc));

		return view;
	}

	public String bidData(String key, int page, int pageSize, Model model) {
		String view = "app/dm/bid-list";

		ProjectionList pl = Projections.projectionList();
		pl.add(Property.forName("id"));
		pl.add(Property.forName("projectNo"));
		pl.add(Property.forName("bidNo"));
		pl.add(Property.forName("name"));

		DetachedCriteria dc = this.bidSrv.getDc(null);
		dc.setProjection(pl);
		dc.addOrder(Order.asc("projectNo"));
		dc.addOrder(Order.asc("name"));
		dc.addOrder(Order.asc("bidNo"));

		if (!StringUtils.isBlank(key)) {
			SimpleExpression r1 = Restrictions.like("projectNo", key, MatchMode.ANYWHERE);
			SimpleExpression r2 = Restrictions.like("bidNo", key, MatchMode.ANYWHERE);
			SimpleExpression r3 = Restrictions.like("name", key, MatchMode.ANYWHERE);

			dc.add(Restrictions.or(r1, r2, r3));
		}

		model.addAttribute("data", this.bidSrv.readByCriteria(dc, page, pageSize));
		model.addAttribute("count", this.bidSrv.getCountByCriteria(dc));

		return view;
	}

	private List<Biddinger> getBiddingers() {
		List<Biddinger> data = this.biddingerSrv.readByEntity(new Biddinger());

		return data == null || data.isEmpty() ? null : data;
	}

	private List<BidAgency> getBidAgencys() {
		List<BidAgency> data = this.bidAgencySrv.readByEntity(new BidAgency());

		return data == null || data.isEmpty() ? null : data;
	}

	private MainContractEditModel storeOldData(Contract data) {
		if (data == null)
			return null;

		MainContractEditModel ret = new MainContractEditModel();

		try {
			PropertyUtils.copyProperties(ret, data);
		} catch (Exception e) {
			return null;
		}

		return ret;
	}

	private BidEditModel storeOldData(Bid data) {
		if (data == null)
			return null;

		BidEditModel ret = new BidEditModel();

		try {
			PropertyUtils.copyProperties(ret, data);
		} catch (Exception e) {
			return null;
		}

		return ret;
	}

}
